/* 
 * jQuery Grid Editor JQuery Plugin  *
 *  license:  *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 *    Freely distributed under the terms of Apache License 2.0. It allows the user of the software the
 *    freedom to use the software for any purpose, to distribute it, to modify it, and to distribute modified
 *    versions of the software, under the terms of the license.
 *
 * jQuery Plugin Options:
 *
 * @name  jgrideditor
 * @type  jQuery
 * @param String  cssURL	   url to the style sheet - if null the default will be used.
 * @param String  postURL 	   POST METHOD URL used to send edited cell content after enter be pressed
 * @param String  getURL	   GET METHOD URL to retrieve asyncronous table data. Used only if no rows is defined
 * @param String  getMsg 	   String Default message that will be displayed when loading row data
 * @param String  postMsg 	   String Default message that will be displayed when posting cell data
 * @param String  menuNew      String Caption of button that trigger the new row append
 * @param String  menuSave     String Caption of button that trigger the save all operation
 * @param Array   cols         Array of json objects which describes the column and their types
 * @param Array   rows         Array of json data that feeds the table. If set getURL is not used 
 * 
 * -------------------------------------------
 *    Data definition sample: 
 *      cols : [  
 *                {id: 'hour', label: 'Hour', editable: false, type: '',  width: 'auto', align: 'right'},
 *                {id: 'name', label: 'Patient Name', editable: true, type: 'input',  width: 'auto',  align: 'left'},
 *                {id: 'phone', label: 'Patient Phone', editable: true, type: 'input', width: 'auto', align: 'right'} 
 *              ]
 *
 *      Notice that "hour", "name" and "phone" must have correspondent values for cols.id
 *      rowid will be send back when posting.
 *      rows : [  
 *                {rowid: 'xyzabc', hour: '13:30', name: 'Machado de assis', phone : 'not applicable'},
 *                {rowid: 'xyzabc', hour: '14:30', name: 'Sylvia Plath', phone : '71 9451-7845'},
 *                {rowid: 'xyzabc', hour: '15:30', name: 'Carl Sagan', phone : '81 8794-7845'}
 *             ]
 *
 *
**/


/**
 * $Id: namespace: gaeinjail v 1.0 2009/10/11 marco@zoqui.com $ 
 * gaeinjail - Namespace Definition
 **/
if (typeof gaeinjail == 'undefined') { var gaeinjail = {}; }
if (typeof gaeinjail.grid == 'undefined') { gaeinjail.grid = {}; }

/**
 * $Id: style v 1.0 2009/10/11 marco@zoqui.com $ 
 * Class style defines the used css 
 **/
gaeinjail.grid.style = function(url){
this.defaultCSS="<style>\
.editabletable {color: #0;border-collapse: collapse;margin: 2px; background-color:transparent; border-left: 1px solid #CCCCCC;border-top: 1px solid #CCCCCC;empty-cells:show;font-family: verdana, tahoma,sans-serif;}\
.editabletable th {background: #BBCCFF;padding-left: 2px;padding-right: 2px;color: #000; border-right: 1px solid #bbbbbb;border-bottom: 1px solid #aaaaaa;font-size: 11px; font-weight:bold;white-space:nowrap;}\
.editabletable tr {height:24px;}\
.editabletable td {padding-left: 2px;padding-right: 3px; border-right: 1px solid #CCCCCC;border-bottom: 1px solid #CCCCCC; color: #000;font-size: 11px; white-space:nowrap;}   \
.editabletable td.lastcell {padding-right: 10px;}\
.editabletable td.disabled {color: #999999;}\
.editabletable td.saving {color: #BBCCFF;}\
.editabletable td span.rowoptions {position:relative; top:-5px;margin-top:0px;margin-left:-9px;background-color: #ffffff;border-top: 1px solid #ffffff;border-left: 1px solid #ffffff;border-right: 1px solid #808080;border-bottom: 2px solid #808080;padding:1px;font-size: 8px;  font-family:tahoma; font-weight:bold;  text-align:center; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px;}\
.editabletable td span.rowoptions:hover{color: #DF7A79;}\
.editabletable td.options {background-color: transparent;}\
.editabletable td.selectedcell {background-color: #E8EEF7;}\
.editabletable .even {background-color: #3D3D3D;}\
.editabletable .odd {background-color: #6E6E6E;}\
.editabletable .header {background-repeat: no-repeat;padding-left: 4px;padding-right: 1px;height: 20px;text-align:center;}\
.editabletable .options {border:none;background-color:transparent;color:#000000;}\
div div.messages {position:absolute;width:auto;border: 1px solid #E50000; background-color: #FFFFFF;z-index:4;text-align:center;font-size: 11px; font-family: tahoma;color:#ff0000;padding:2px;}\
.editabletable input.celinput {position:relative; border:none; font-family: verdana, tahoma,sans-serif; margin-left:-1px; margin-rigth: 3px;top:0;background-color:transparent; height: 100%; padding: 0 0; font-size: 11px; text-transform:uppercase;}\
.editabletable input.celinput:focus {border:none;outline:none;background-color: transparent;}\
.editabletable form.celform {overflow:hidden;position:relative; padding: 0px 0px; margin: 0px 0px; height:100%;width:100%;}\
.temporary {color: #AA3F3F;text-align: center;margin-left: auto;margin-right: auto;font-size: 11px;}\
.totalstable {color: #0; display:none;border-collapse: collapse;margin: 0px; background-color:transparent; empty-cells:show;font-family: verdana, tahoma,sans-serif;}\
.totalstable tr {height:24px;}\
.totalstable td {margin-left:2px;padding-left: 2px;padding-right: 3px; color: #000;font-size: 11px; white-space:nowrap;}\
div.menu {background-color:transparent;font-family: tahoma,verdana,sans-serif; font-size: 13px; font-weight:bold;color: #a0a0a0;}\
div.menu span:hover{color: #DF7A79;}\
div.autosuggest {background-color: transparent;position: fixed;padding: 0 0 0 0;z-index:9999; overflow: visible;  display:inline;  font-size: 1em;  font-family: verdana,tahoma,sans-serif;}\
div.autosuggest div.as_header,div.autosuggest div.as_footer{ position: relative; height: 0px; padding: 0 0px; overflow: hidden;}\
div.autosuggest ul{ background-color: #FCFBF9; list-style: none; margin: 0 0 -12px 0; padding: 0; overflow: hidden; border-right:thick ridge #F3F1E9; border-bottom:thick ridge #F3F1E9; border-left:thin solid #F3F1E9;}\
div.autosuggest ul li{  padding: 0; margin: 0 2px 2px; text-align: left;}\
div.autosuggest ul li a{  color: #DF7A79;  display: block; text-decoration: none; text-shadow: #ccc 1px 0px 1px; position: relative; padding: 0; width: 100%;}\
div.autosuggest ul li.as_highlight a:hover{ color: #DF7A79; background-color: #F3F1E9;}\
div.autosuggest ul li a span{ display: block; padding: 1px 2px; font-weight: bold;}\
div.autosuggest ul li a span small{ font-weight: normal; color: #98ACB8;}\
div.autosuggest ul li.as_highlight a span small{ color: #98ACB8;}\
div.autosuggest ul li.as_highlight a{ color: #DF7A79;  background-color: #EFEBDE;}\
div.autosuggest ul em{ font-style: normal; color: #C91919;}</style>";
    // Default styles?
    if (url===""){
        $("head").append(this.defaultCSS);
    }
    else{
        $("head").append('<link rel="stylesheet" type="text/css" media="screen" href="'+url+'" />');
    };
};

/**
 * $Id: warn v 1.0 2009/10/11 marco@zoqui.com $ 
 * Class wan create a warn message into container
 **/
gaeinjail.grid.warn = function(containerid, msg, wait)
{
    var div = $("#"+containerid+' .messages');
    if (div.length==0){
       div = $("#"+containerid).append('<div class="messages" style=""></div>').find("div");
    }
    else{
       var tbl = $("#"+containerid).find("table");
       if (tbl.length>0){
           var x = tbl[0].offsetLeft;
           div.css("left",x);
       }
    }
    div.text(msg);
    if (wait<1000){
        div.show().click(function(){
            $(this).hide();
        });
    }
    else{
        div.show(wait);
    }
};

/*
 * $Id: Json2Table v 1.0 2009/04/18 marco@zoqui.com $ 
 * Class Json2Table Translate a JSData to a table
 **/
gaeinjail.grid.JSON2Table = function() 
{
    // Attributes
    this.bufCols = new Array();
    this.bufRows = new Array();
    this.bufTots = new Array();
    this.hasTotals = false;
    this.rows = [];
    this.cols = []; 

    this.emptyRow = [];
    this.hasOptions = [];

    this.width = 0;
    /**
     * a cell text-align can be defined with align property. 
     * @Returns the style string by default
     **/
    this.getColAlign = function(i, asStyle){
        var ret = 'left';
        asStyle = (!asStyle) ? true : !(asStyle==false);
        if (typeof(this.cols[i].align)=='string')
            ret=this.cols[i].align;
        if (asStyle)
            ret="text-align:" + ret + ";";
        return ret;
    };

    /**
     * a cell width can be defined with width property in pixels (px)
     * @Returns the style string by default
     **/
    this.getColWidth = function(i, asStyle){
        var ret = '20px';
        asStyle = (!asStyle) ? true : !(asStyle==false);
        if (typeof(this.cols[i].width)=='string')
            ret=this.cols[i].width;
        	this.width+=parseInt(ret.replace(/px/ig,''));
        if (asStyle)
            ret="min-width:" + ret + ";max-width:" + ret + ";";
        return ret;
    };

    /**
     * set the columns (field names) to the table
     **/    
    this.setCols = function(cols){
    	var colIndex=[]
        this.cols = cols;
    	this.bufCols.push("<tr>");
        for(var iCol=0;iCol<this.cols.length;iCol++){
        	this.cols[iCol]['sequence']=iCol;
        	this.cols[iCol]['sum']=0;
        	this.cols[iCol]['max']=0;
        	this.cols[iCol]['min']=0;
            if (this.cols[iCol].id==='options'){
            	this.hasOptions=true;       	
            }
            else{
                this.bufCols.push('<th class="field" style="'+this.getColWidth(iCol,true)+'">' + this.cols[iCol].label + '</th>');
            }
            colIndex[this.cols[iCol].id]=this.cols[iCol];
//            if (this.cols[iCol].calcsum)
//            	this.hasTotals=true;
        };
        this.bufCols.push("</tr>");
        return colIndex;
    };

    this.addRow = function(rowid,row){
        var buf = new Array();
        var value = null;
    	buf.push('<tr id="'+rowid+'" class="editabletablerow">');
        if (rowid<0){
            this.emptyRow['rowid']=-1;
        }
        for(iCol=0;iCol<this.cols.length;iCol++){
            var propname = this.cols[iCol].id;
            value = row[propname];
            // It checks if an extra col was defined (no row)
            // this extra col (without any label) will be used to update/delete complete row
            if (propname==='options'){
                var rowDelHtml = '<span class="rowoptions">&nbsp;X&nbsp;</span>';
                buf.push('<td class="options">'+rowDelHtml+'</td>');
            }
            else{
            	var cls=[];
            	if (iCol==this.cols.length-2)
            		cls.push("lastcell");            		
            	if (!this.cols[iCol].editable)
            		cls.push("disabled");
            	var clsstr = '';
            	if (cls.length>0)
            		clsstr='class="'+cls.join(" ")+'"';
            	if (value){
                    buf.push('<td '+clsstr+' style="'+this.getColAlign(iCol)+'">'+value+'</td>');
                }
                else{
                    buf.push('<td '+clsstr+' style="'+this.getColAlign(iCol)+'"></td>');
                }
                if (rowid<0){
                    this.emptyRow[propname]=value;
                }
            }
        };
        buf.push("</tr>");
        return buf.join('');
    };

    this.setRows = function(rows){
        this.rows = rows;
        var sample = null;
        for(iRow=0;iRow<rows.length;iRow++){
            var row = this.rows[iRow];
            var rowid = 'Row'+iRow;
            if (row['rowid'])
                rowid=row['rowid'];
            this.bufRows.push(this.addRow(rowid,row));
        };
    };

    this.getAsHtml = function(){
        var ret= '<table class="editabletable">' + this.bufCols.join('') + this.bufRows.join('') + '</table>';
        if (this.hasTotals){
        	this.buildTots();
        	ret=ret+'<table class="totalstable" style="display:block;">' + this.bufTots.join('') + '</table>';        	
        }
        return ret;
    };
    
    /**
     * set the columns (field names) to the table
     **/    
    this.buildTots = function(){
    	this.bufTots.push("<tr>");
        for(var iCol=0;iCol<this.cols.length;iCol++){
            if (this.cols[iCol].id!=='options'){
                this.bufTots.push('<td class="totalscell" style="'+this.getColWidth(iCol,true)+this.getColAlign(iCol)+'">&nbsp;</td>');
            }
        };
        this.bufTots.push("</tr>");
    };
    
}; 

/**
 * $Id: GridEditor v 1.0 2009/04/18 marco@zoqui.com $ 
 * Class GridEditor Handle document events for html table editing
 **/
gaeinjail.grid.Editor = function(id, settings)
{
    // Properties
    this.id = id; // divId
    this.settings = settings;
    this.editing = false;
    this.selRow=1;
    this.selCol=0;
    this.nRows=0; 
    this.nCols=0; 
    this.lastchar='';
    this.isCtrl=false;
    this.KeyCodeMap = {
        pagedown:  34,
        right  	:  39, 
        down   	:  40,
        pageup 	:  33,
        end		:  35,
        home	:  36,
        left   	:  37, 
        up     	:  38,
        esc    	:  27,
        enter  	:  13,
        tab	    :   9,
        f2	    : 113,
        f4	    : 115,
        ins		:  45,
        del	    :  46
    };
    // Returns true if the table is valid
    this.isReady = function(){
        return ((this.nRows!==0)&&(this.nCols!==0));
    };

    // Initialize the object
    this.init = function(){
	    this.lastchar='';
	    this.isCtrl=false;
        this.cells = $("#" + this.id + " > table td");
        //this.nRows=$("#" + this.id + " > table tr").length; 
        //this.nCols=Math.round(this.nRows>0 ? $("#" + this.id + "> table td,th").length/this.nRows : 0);
        this.nRows=this.settings.rows.length+1;
        this.nCols=this.settings.cols.length;
        if (this.isReady()){
        	if (this.settings.enableTotals){
//        		$('table.totalstable').css('display','block');
//        		this.calcsum();
        	}
            this.activateCell(this.selRow, this.selCol);
            this.listenKeyboard();
            return true;
        }
        return false;
    };

    this.checkToDelete = function(r){
    	if (this.nCols<=1 || (r < 1 ||r > this.nRows-1)) 
    		return;
    	var c = this.nCols-1;
    	var sel = "#" + this.id + " > table tr:eq(" + r + ") td:eq(" + c + ")";
        var cel = $(sel);
        if (cel.hasClass("options")){
        	cel.find(".rowoptions").click();
        };
    };
    // Set the current selection
    this.activateCell = function(r, c){
        if ((this.nRows===0)||(this.nCols===0))
            return;	// Not Initialized
        if (r>this.nRows-1)
            r=this.nRows-1;
        else if (r<1)
            r=1;
        if (c>this.nCols-1)
            c=this.nCols-1;
        else if (c<0)
            c=0;

        // check target
        var sel = "#" + this.id + " > table tr:eq(" + r + ") td:eq(" + c + ")";
        var cel = $(sel);
        if (cel.hasClass('totalscell'))
        	return $(".selectedcell");
        if (!cel.is(':visible')||cel.hasClass("options")||cel.hasClass("field")){
            if (r>this.selRow && r+1<this.nRows)
                return this.activateCell(r+1, c);
            else if (r<this.selRow && r-1>=1)
                return this.activateCell(r-1, c);
            else
                return $(".selectedcell");
        }
        if (!this.settings.cols[c].editable){
        	if (this.selCol<c && (c+1<this.nCols-1)){
        		return this.activateCell(r, c+1);// jump one right
        	}
        	else if (this.selCol>c && (c>1)){
        		return this.activateCell(r, c-1);// jump one left
        	}
        }
        $(".selectedcell").removeClass("selectedcell");
        var activeCell = cel;
        activeCell.addClass("selectedcell"); 
        this.selRow=r;
        this.selCol=c;
        return activeCell;
    };

    // Process the keydown event on the document
    this.listenKeyboard = function(){
        var self = this; // keep context
        if (!self.isReady()) 
            return;
        this.isCtrl=false;

        $(document).keyup(function(e){
            if (e.which==17){
               self.isCtrl=false;	
            }
        }).keydown(function(e) {
            if (self.editing) return;
            self.lastchar='';
            if (e.which==17){
               self.isCtrl=true;
               return;   
            }
            switch (e.keyCode) {
            case self.KeyCodeMap.esc:
                $(".messages").hide();
                e.preventDefault();
                break;
            case self.KeyCodeMap.f2:
                e.preventDefault();
                $(".selectedcell").click();
                break;           		
            case self.KeyCodeMap.tab:
            	if (e.shiftKey)
                    self.activateCell(self.selRow,self.selCol-1);
                else
                    self.activateCell(self.selRow,self.selCol+1);
            	e.preventDefault();
            	break;
            case self.KeyCodeMap.left:
                self.activateCell(self.selRow,self.selCol-1);
                e.preventDefault();
                break;
            case self.KeyCodeMap.right:
                self.activateCell(self.selRow,self.selCol+1);
                e.preventDefault();
                break;
            case self.KeyCodeMap.enter:
            case self.KeyCodeMap.down:
                self.activateCell(self.selRow+1,self.selCol);
                e.preventDefault();
                break;
            case self.KeyCodeMap.home:
            	self.activateCell(1,self.selCol);
            	e.preventDefault();
            	break;
            case self.KeyCodeMap.end:
            	var r = self.selRow;
            	if (self.nRows>2){
	            	self.activateCell(self.nRows-1,self.selCol);
	            	if (self.nRows>3 && r==self.selRow)
	            		self.activateCell(self.nRows-2,self.selCol);
            	}
            	e.preventDefault();
            	break;
            case self.KeyCodeMap.up:
                self.activateCell(self.selRow-1,self.selCol);
                e.preventDefault();
                break;
            case self.KeyCodeMap.ins:
                e.preventDefault();
                if (e.ctrlKey){
                	$("#rowins").click();
                }
                break;
            case self.KeyCodeMap.del:
                e.preventDefault();
                if (e.ctrlKey){
                    self.checkToDelete(self.selRow);
                }
                else{
                    self.lastchar = 'DEL';
                    $(".selectedcell").click();
                }
                break;
            default:
                if ((e.keyCode>=65&&e.keyCode<=90)||(e.keyCode>=48&&e.keyCode<=57)||(e.keyCode>=96&&e.keyCode<=105)){
                    if (self.isCtrl){
                        switch (e.keyCode) {
                            case 78:
                            case 73: // Ctrl-I
                                e.preventDefault();
                                $("#rowins").click();
                                break;
                            case 68: //Ctrl-D                	
                                e.preventDefault();
                                self.checkToDelete(self.selRow);
                                break;
                            case 83: //Ctrl-S
                                e.preventDefault();
                                $("#saveall").click();
                                break;
                        }
                        return;
                    }
                    e.preventDefault();
                    if (e.keyCode>=90&&e.keyCode<=105)
                        self.lastchar = String.fromCharCode(e.keyCode-48);
                    else
                        self.lastchar = String.fromCharCode(e.keyCode);
                    $(".selectedcell").click();
                }
            }
        });
    };

    this.calcsum = function(){
    	var self=this;
		setTimeout(function(){
            $(".editabletablerow").each( function(i){
            	if (i==0){
            		$('.totalstable td').text('');
            		for(var iColSum=0;iColSum<self.settings.cols.length-1;iColSum++){
            			self.settings.cols[iColSum].sum=0;
            		}
            	}
                if ($(this).is(":visible")){
                	for(var iColSum=0;iColSum<self.settings.cols.length-1;iColSum++){
                		if (self.settings.cols[iColSum].calcsum){
                    		var sel="tr#" + $(this).attr('id') + " td:eq(" + iColSum + ")";
                    		var vlr=parseFloat($(sel).text());
                    		if(!isNaN(vlr)){
	                    		self.settings.cols[iColSum].sum+=vlr;
	                    		sel="table.totalstable tr:eq(0) td:eq(" + iColSum + ")";
	                    		var vlr=$(sel).text(self.settings.cols[iColSum].sum);
                    		}
                		}
                	}
                }
			});                       			
		},5);
    };
    
    this.enable = function(){
        var self = this; // keep context
        if (!self.isReady())return;		
        // loop on cells
        $(this.cells).each( function(i) {
            $(this)['click']( function(){
                $(".messages").hide();
                if ($(".celinput").is(':visible')){
                	//$(".celinput").focus();
                	return;
                }
                if ($(this).hasClass('totalscell'))
                	return;
                self.editing=true;
                $(".editabletablerow").css("background-color","transparent");
                var row  = parseInt(i/self.nCols);
                var col  = parseInt(i%self.nCols);
                var cell = self.activateCell(row+1,col);
                if (!self.settings.cols[col].editable){
                	self.editing=false;
                	return;      
                }
                //var cell = this;
                var rowid = $(cell).parent().get(0).id
                //var width=self.settings.cols[col].width;
                var width=$(cell).css('width');
                cell.previousHtml = $(this).html();
                cell.previousData = $(this).text();
                navEnable = false;     
                var direction = 0; //0=same;1=down;2=right
                var deleting = false;
                if (self.lastchar==''){
                    frmhtml='<form id="editcelform" style="width:'+width+';" class="celform"><input type="text" name="'+self.settings.cols[col].id+'" class="celinput" value="'+cell.previousData+'"/></form>';
                }
                else{
                    if (self.lastchar=="DEL"){
                        frmhtml='<form id="editcelform" style="width:'+width+';" class="celform"><input type="text" name="'+self.settings.cols[col].id+'" class="celinput" value=""/></form>';
                        deleting=true;
                    }
                    else{
                        frmhtml='<form id="editcelform" style="width:'+width+';" class="celform"><input type="text" name="'+self.settings.cols[col].id+'" class="celinput" value="'+self.lastchar+'"/></form>';
                    }
                }
                self.lastchar="";
                $(cell).html(frmhtml);
                if (deleting){
                    ajaxPost();
                }
                else{
                    if (self.settings.cols[col].choices){
                        $(".celinput").attr('id','celinput')
                        var as_options= {
                			script: function(typedstr){
                        		var choices=self.settings.cols[col].choices;
                            	items=[];
                        		for (var i=0;i<choices.length;i++){
                                    if (typedstr.length>0){
                                    	var pattern = new RegExp('\\b'+typedstr,"i");
	                                    if (choices[i].search(pattern)>=0){
	                                		items.push({'id':i,'value':choices[i]});
	                                    }
                                    }
                                    else{
                                    	items.push({'id':i,'value':choices[i]});
                                    }
                            	}
                        		return items;
                        	},
                			varname:self.settings.cols[col].id,
                			json:true,
                			timeout:1500,
                			delay:10,
                			shownoresults:false,
                			noresults:false,
                			minchars:0,
                			callback: function(obj, varname, typedstr){
                        		if (obj)
                        			$(".celform").submit();
                        		else
                        			reset();
                        		return;
                        	}
                    	};
                        var as_json = new AutoSuggest("celinput", as_options);
                    	$(".celinput").focus();
                    }
                    else{
                        if (self.settings.cols[col].sourceURL){
                            $(".celinput").attr('id','celinput');
                            var as_options= {
                    			script:self.settings.cols[col].sourceURL,
                    			varname:self.settings.cols[col].id,
                    			json:true,
                    			timeout:1500,
                    			delay:10,
                    			shownoresults:false,
                    			noresults:false,                    			
                    			callback: function(obj, varname, typedstr){
	                        		if (obj){
	                            		self.settings.rows[row][varname+'_newRefId']=obj.id;
	                            		$(".celinput").attr('newRefId',obj.id);
	                            		$(".celform").submit();                            		
	                        		}
	                        		else{
	                           			reset();
	                        		}
                           			return;
                        		}
                        	};
                            var as_json = new AutoSuggest("celinput", as_options);
                        	$(".celinput").focus();
                        }
                        else{
                        	if (self.settings.cols[col].mathparser){
                        		$(".celinput").mathparser({});
                        	}
                        	$(".celinput").attr('autocomplete','off').keydown(function(e){
                        		switch (e.keyCode){
                                case self.KeyCodeMap.esc:
                                    e.preventDefault();
                                    e.stopPropagation();
                                    direction=0;
                                    reset();
                                    break;
                                    return false;
                                case self.KeyCodeMap.tab:
                                    e.preventDefault();
                                    e.stopPropagation();
                                    direction=2;
                                    $(".celform").submit();
                                    break;
                                    return false;
                                case self.KeyCodeMap.enter:
                                case self.KeyCodeMap.down:
                                    e.preventDefault();
                                    e.stopPropagation();
                                    direction=1;
                                    $(".celform").submit();
                                    break;
                                    return false;
                                }
                            	return true;                           	
                            }).focus();
                    		setTimeout(function(){
                    			$(".celinput")[0].selectionStart=$(".celinput")[0].value.length;
                    		}, 0);
                        }
                    }         
                    var timer;
                    $(".celinput").blur( function(e){
                        timer = setTimeout(reset, 10);
                    });
                };

                $(".celform").submit( function(e) {
                    if (timer) { 
                        clearTimeout(timer);
                    }
                    e.preventDefault();
                    ajaxPost();
                });
                
                function moveNext(direction){
                    if (direction==2)
                    	self.activateCell(self.selRow,self.selCol+1);
                    else if (direction==1){
                    	if (self.nRows-1==self.selRow)
                    		self.activateCell(self.selRow,self.selCol+1);
                    	else
                    		self.activateCell(self.selRow+1,self.selCol);
                    }
                };
                
                function ajaxPost(){
                    // Ajax Posting...
                	var JQobj=$(".celinput");
                	var cellData = JQobj.val().toUpperCase();
                	var fldNam = JQobj.attr('name');
                    var fldVal = JQobj.attr('newRefId');
                    if (!fldVal)
                    	fldVal=cellData ;
                    if (cellData==cell.previousData){
                    	self.editing=false;	
                    	setTimeout(reset, 2);
                    	moveNext(direction);
                    }
                    else{
                    	var oldColor = $(cell).html(cellData).css("color");
                    	var postData = {};
	                    postData['fieldname']  	= fldNam;
	                    postData['fieldvalue'] 	= fldVal;
	                    postData['row']		   	= row; 
	                    postData['col'] 	   	= col;
	                    postData['rowid']		= rowid;	                    
	                    //$(cell).css("color","#3D3D3D"); 
	                    $(cell).addClass('disabled');
	                    if (self.settings.postURL===''){
	                        $(cell).text(cellData);
	                    }
	                    else{
	                        jQuery.post(self.settings.postURL, postData, function(str) {
	                            var resp = eval('(' + str + ')');
	                            if (typeof(resp) != "object" || resp.sts=="ERROR"){
	                                gaeinjail.grid.warn(settings.id,resp.msg,0);
	                                setTimeout(reset, 1000);
	                            }
	                            else{
	                            	clr=oldColor;
                                    if (resp.color && resp.color!=undefined && resp.color!=null)
                                    	clr=resp.color;
                                    $.each(resp.updated,function(k,v){
                                    	var seq=settings.colIndex[k].sequence;
                                    	var sel="tr#" + rowid + " td:eq(" + seq + ")";
                                    	var el=$(sel);
                                    	if (el[0]){
                                    		if (settings.colIndex[k].editable)
                                    			el.text(v).removeClass('disabled');
                                    		else
                                    			el.text(v);
//                                    		if (settings.enableTotals && settings.colIndex[k].calcsum){
//                                    			self.calcsum();
//                                    		}
                                    	}
                                    })
                                    //$(cell).text(resp.updated[fldNam]).css("color",clr);
	                                moveNext(direction);
	                            }
	                            self.editing=false;							
	                        });
	                    };
	                    return;
                    }
                };
                function reset() {
                    $(cell).html(cell.previousHtml).css("color","#000000");
                    self.editing=false;
                };
            });
        });
    };
};


//JQuery Plugin Function
gaeinjail.grid.Plugin = function(options) 
{
    var editor = null;
    var settings = {
        id                : '',
        cssURL        	  : '',
        postURL           : '',
        getURL            : '',
        getMsg            : 'Loading...',
        postMsg           : 'Saving...',		
        menuNew           : '(I)nsert',
        menuSave          : '(S)ave',
        cols        	  : [],
        rows              : [],
        emptyRow          : [],
        colIndex		  : [],
        enableTotals	  : false                		     
    };
    if(options) {
        jQuery.extend(settings, options);
    };

    // My Id
    var myId = $(this).attr("id");
    settings.id = myId;

    // Are there any cols?
    if (settings.cols.length===0){
        $(this).append('Field array not defined');
        return $(this);
    };

    // Load necessary css
    var gridstyle = new gaeinjail.grid.style(settings.cssURL);	

    /*
     * Create a Editor object that will handle this grid
     */
    function edit(){
        if (editor){
            editor.enable();
        }
        else{
            editor = new gaeinjail.grid.Editor(myId,settings);
            if (editor.init()){
                editor.enable();
            }
        }
    }

    /*
     * Send a complete row to the appengine
     */
    function updateRow(trsel,iRow){
		var self = this; // keep context
		var rowid = trsel[0].id;
		var sel = "#"+rowid+" > td";
 
        // verify changes		
        var isPending=false;
        var preCheck=[];
        var row = null;
        if (iRow>=0)
            row=settings.rows[iRow];
        if (!row) return;
        
        // insert/update/delete command?
        var cmd='';
        if ($(sel + " .rowoptions").css("backgroundColor")=="rgb(255, 255, 255)"){
            cmd=(rowid<0)?'rowins':'rowupd';						
        }
        else{
            cmd="rowdel";
            if (rowid<1){
                cmd="restore";
            }
        }
        // prepare properties for posting
        var postData = {};
        postData['rowid'] = rowid;
        postData['options'] = cmd;        
        if (cmd==='rowdel'){
        	isPending=true;
        }
        else{
	        $(sel).each(function(tdIndex){
	            var propname = settings.cols[tdIndex].id;
	            if (propname!=='options'){
	                var newvalue = null;
	                if (cmd==='restore'){
	                    $(this).text('');
	                }
	                else{
	                    if (settings.cols[tdIndex].sourceURL==null){
	                        //text from cell
	                        newvalue = $(this).text();
	                        var oldvalue = row[propname];
	                        if ((oldvalue==null) || (oldvalue==undefined))
	                           oldvalue="";
	                        if (newvalue!=oldvalue){
	                            isPending=true;
	                            row[propname]=newvalue;
	                        }
	                    }
	                    else{
	                        //refid
	                        newvalue = row[propname+'_newRefId'];
	                        var oldvalue = row[propname+'_oldRefId'];
	                        if (oldvalue==undefined || oldvalue==null)
	                        	oldvalue='';
	                        if (newvalue!=undefined && newvalue != null){
	                            if (newvalue!=oldvalue){
	                                isPending=true;
	                                row[propname+'_oldRefId']=newvalue;
	                            }
	                        }
	                    }
	                    if (settings.cols[tdIndex].required){
	                    	if (newvalue==null || newvalue == undefined || newvalue=='' || newvalue.length==0){
	                    		//preCheck.push('[#'+rowid+' '+propname+'] Invalid Value');
	                    		preCheck.push('[#'+rowid+' '+propname+'] Invalid Value');
	                    		$(this).html('<span style="color:red;">Invalid Value</span>').find('span').fadeOut(5000,function(){
	                    			$(this).parent().html('');
	                    		});
	                    	}
	                    	else{
	                    		postData[propname] = newvalue;	
	                    	}
	                    }
	                    else{
	                    	if (newvalue==null||newvalue==undefined||newvalue==''||newvalue.length==0)
	                    		newvalue='';
                    		postData[propname] = newvalue;
	                    }
	                }
	            }
	        });
        }
        if (cmd==='restore'){
        	trsel.hide();
        	$(sel + " .rowoptions").css("backgroundColor","#FFFFFF");
        }
        else{
	        if (isPending){
	        	var faderow = null;
	            if (cmd!=='rowdel'){
	            	//faderow = $("#"+rowid+" > td").fadeOut("slow");
	            	if (preCheck.length>0){
	            		//gaeinjail.grid.warn(settings.id,preCheck.join('<br/>'),0);
	            		return;
	            	}
	            	else{
		            	faderow = $("#"+rowid+" > td").addClass("saving");	            		
	            	}
	            }
	            jQuery.post(settings.postURL, postData, function(str) {
	                var resp = eval('(' + str + ')');
	                if (faderow){
	                	//faderow.fadeIn("fast");
	                	faderow.removeClass('saving'); 
	                }
	                
	                if (resp.sts=="ERROR"){
	                    gaeinjail.grid.warn(settings.id,resp.msg,0);
	                }
	                else{
	                    if (cmd==='rowdel'){
	                        trsel.hide();
	                    }
	                    else if (cmd==='rowins'){
	                       if (resp.rowid>0){
	                          var prevTR = $("#"+rowid); 
                              var newid = resp.rowid; 
                              prevTR.attr('id',newid);
	                          row['rowid']=newid;                      
	                       }
	                    }
	                    if (settings.enableTotals)
	                    	editor.calcsum();
	                }
	            });
	        }
        }
     };

	/*
     * Creates the table inside the given node (div) and call the editor
     */	
	if (settings.rows.length>0){
        var tbl = new gaeinjail.grid.JSON2Table();
        settings.colIndex=tbl.setCols(settings.cols);
        settings.enableTotals=tbl.hasTotals;
        tbl.setRows(settings.rows);
        $("#"+myId).append(tbl.getAsHtml());        
        edit();
	}
	else{
        if (settings.getURL === ''){
            gaeinjail.grid.warn(myId,"getURL not defined",3000);
        }
        else{
            gaeinjail.grid.warn(myId,settings.getMsg,5000);
            function getRows(){
                $.ajax({type: "GET",url:settings.getURL,dataType:"script",success: 
                function(jsonObject){
                    $("#"+myId).find("div").hide()
                    var tbl = new gaeinjail.grid.JSON2Table();
                    settings.colIndex=tbl.setCols(settings.cols);
                    settings.enableTotals=tbl.hasTotals;
                    tbl.setRows(eval('(' + jsonObject + ')'));
                    settings.rows = tbl.rows;
                    settings.emptyRow = tbl.emptyRow.slice(0);
                    $("#"+myId).append(tbl.getAsHtml());
                    if (tbl.hasOptions){
                    	var htmlNew = '';
                    	var htmlUpd = '';
                    	if (settings.menuNew === '')
                    		htmlNew = '<span id="rowins" style="display:none;"></span>';
                    	else
                    		htmlNew = '<span id="rowins">'+settings.menuNew+'&nbsp;&nbsp;</span>';
                    	if (settings.menuSave === '')
                    		htmlUpd = '<span id="saveall" style="display:none;"></span>';
                    	else
                    		htmlUpd = '<span id="saveall">'+settings.menuSave+'</span>';
                    	var mainmenu = '<div style="width:'+tbl.width.toString()+'px;text-align:center;">'+htmlNew+htmlUpd+'</div>';
                    	if (mainmenu!=='<div></div>')
                    		$("#"+myId).append(mainmenu).find('div').addClass("menu");                    	
                    }
                    $("div > div.messages").css('width',tbl.width.toString()+'px');
                    if (tbl.rows.length>1)
                        $("#-1.editabletablerow").hide();
                    $(".editabletablerow").hover(
                        function () {
                            var frm  = $("#editcelform").is(':visible');
                            if (!frm){
                                $(this).css("backgroundColor","#f0f0f0");
                            }
                        }, 
                        function () {
                            $(this).css("backgroundColor","transparent");
                        }
                    );
                    // Delete Mark
                    $(".rowoptions").click( function(e){
                        $(".messages").hide();
                        var opt = $(this); 
                        var color = opt.css("backgroundColor");
                        opt.css("backgroundColor", (color=="rgb(255, 255, 255)") ? "#ffaaaa" : "#ffffff");
                        e.preventDefault();
                        e.stopImmediatePropagation();
                    }).hover(
                       function(){
                           $(this).css('cursor','pointer');
                       },
                       function(){
                           $(this).css('cursor','default');
                       }
                    );
                    
                    $("#saveall").click(function(){
                    	if ($(this).is(":visible"))
                    		$(this).fadeOut("slow").fadeIn("fast");
                        $(".messages").hide();
                        var lastid = -1;
                        if (settings.rows.length>=2) 
                            lastid=settings.rows[settings.rows.length-2]['rowid'];
                        $(".editabletablerow").each( function(i){
                            if ($(this).is(":visible"))
                               updateRow($(this),i);
                        });
                    });
                    
                    $("#rowins").click(function(){
                        if ($(this).is(":visible"))
                        	$(this).fadeOut("slow").fadeIn("fast");
                        var last = $("#-1.editabletablerow");
                        if (last.length>0){
    	                    $(".messages").hide();
                            last.fadeIn(500);
    	                    if (editor.nRows>2)
    	                        editor.activateCell(editor.nRows-1,0);
                        }
                        else{
                        	var table = $("#"+myId+" > table");
                        	settings.rows.push(settings.emptyRow.slice(0));
                        	var jsonTbl = new gaeinjail.grid.JSON2Table();
                        	settings.colIndex=jsonTbl.setCols(settings.cols);
                        	var html = jsonTbl.addRow(-1,settings.emptyRow);
    						table.append(html);
    	                    last = $("#-1.editabletablerow");
    	                    if (last.length>0){
    		                    $(".messages").hide();
    		                    editor.lastchar='';
    		            	    editor.isCtrl=false;
    		            	    editor.cells = $("#" + myId + " > table td");
    		                    editor.nRows=editor.nRows+1; 
    		                    last.show();
    		                    if (editor.nRows>2){
    		                        editor.activateCell(editor.nRows-1,0);
    		                        editor.enable();
    		                    }
    	                    }
                        }
                    });
                    edit();
                }});
            };
            setTimeout(getRows, 0);
        }
	}
	return(this);
};





//Bind jQuery

jQuery.fn.jgrideditor = gaeinjail.grid.Plugin;
